package com.googlecode.mapperdao

import com.googlecode.mapperdao.jdbc.Setup
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.{FunSuite, Matchers}

/**
 * @author kostantinos.kougios
 *
 *         Jan 19, 2012
 */
@RunWith(classOf[JUnitRunner])
class ManyToOneExternalEntitySuite extends FunSuite with Matchers
{
	val (jdbc, mapperDao, queryDao) = Setup.setupMapperDao(List(PersonEntity, HouseEntity))

	if (Setup.database == "h2") {

		test("delete") {
			createTables()

			val person = Person("kostas", House(10, "name10"))
			val inserted = mapperDao.insert(PersonEntity, person)
			mapperDao.delete(PersonEntity, inserted)
			HouseEntity.deleted should be(null)
			mapperDao.select(PersonEntity, inserted.id) should be(None)
		}

		test("delete with propagate") {
			createTables()

			val person = Person("kostas", House(10, "name10"))
			val inserted = mapperDao.insert(PersonEntity, person)
			mapperDao.delete(DeleteConfig(propagate = true), PersonEntity, inserted)
			HouseEntity.deleted should be(person.house)
			mapperDao.select(PersonEntity, inserted.id) should be(None)
		}

		test("insert/select") {
			createTables()

			val person1 = Person("kostas", House(10, "name10"))
			val inserted1 = mapperDao.insert(PersonEntity, person1)
			inserted1 should be(person1)
			val person2 = Person("kostas", House(20, "name20"))
			val inserted2 = mapperDao.insert(PersonEntity, person2)
			inserted2 should be(person2)

			mapperDao.select(PersonEntity, inserted1.id).get should be(inserted1)
			mapperDao.select(PersonEntity, inserted2.id).get should be(inserted2)
		}

		test("update") {
			createTables()

			val person = Person("kostas", House(10, "name10"))
			val inserted = mapperDao.insert(PersonEntity, person)
			HouseEntity.updateCalled should be(1)
			val toUpdate = Person("kostas", House(20, "name20"))
			val updated = mapperDao.update(PersonEntity, inserted, toUpdate)
			updated should be(toUpdate)

			HouseEntity.updateCalled should be(2)

			mapperDao.select(PersonEntity, inserted.id).get should be(updated)
		}

		test("query for external entity id") {
			createTables()

			val person = Person("kostas", House(10, "name10"))
			mapperDao.insert(PersonEntity, person)

			import com.googlecode.mapperdao.Query._
			queryDao.query(select from pe where pe.house === person.house) should be(List(person))
		}
	}

	def createTables() {
		HouseEntity.reset()
		Setup.dropAllTables(jdbc)
		Setup.queries(this, jdbc).update("ddl")
	}

	case class Person(name: String, house: House)

	case class House(id: Int, name: String)

	val pe = PersonEntity

	object PersonEntity extends Entity[Int, SurrogateIntId, Person]
	{
		val id = key("id") autogenerated (_.id)
		val name = column("name") to (_.name)
		val house = manytoone(HouseEntity) to (_.house)

		def constructor(implicit m: ValuesMap) = new Person(name, house) with Stored
		{
			val id: Int = PersonEntity.id
		}

	}

	object HouseEntity extends ExternalEntity[Int, House]
	{
		val id = key("id") to (_.id)
		val m = scala.collection.mutable.Map.empty[Int, House]

		def reset() {
			deleted = null
			m.clear()
			updateCalled = 0
		}

		var updateCalled = 0
		onUpdateManyToOne(PersonEntity.house) {
			case UpdateExternalManyToOne(updateConfig, house) =>
				updateCalled += 1
				m(house.id) = house
		}

		onSelectManyToOne(PersonEntity.house) {
			case SelectExternalManyToOne(selectConfig, primaryKeys) =>
				primaryKeys match {
					case List(id: Int) => m(id)
					case _ => throw new IllegalStateException
				}
		}

		var deleted: House = _
		onDeleteManyToOne {
			d =>
				deleted = d.foreign
		}
	}

}